﻿using System;
using System.Collections.Generic;

namespace CPAIS.Model
{
    /// <summary>
    /// Enumerates the sex type of human.
    /// </summary>
    public enum SexType
    {
        Unknown,
        Male,
        Female
    }

    /// <summary>
    /// Represents a clinical patient trace.
    /// </summary>
    public class Trace
    {
        #region Variables in Trace
        private LogModel owner;
        private string id;
        private List<int> diagnoses;
        private List<ObservationEvent> observations;
        private List<ActionEvent> actions;
        #endregion

        /// <summary>
        /// Constructor with patient ID.
        /// </summary>
        /// <param name="owner">Owner LogModel</param>
        /// <param name="id">Patient ID</param>
        public Trace(LogModel owner, string id)
        {
            if (owner == null)
                throw new ArgumentNullException("owner");
            if (string.IsNullOrEmpty(id))
                throw new ArgumentNullException("id");
            this.owner = owner;
            this.id = id;
            diagnoses = new List<int>();
            observations = new List<ObservationEvent>();
            actions = new List<ActionEvent>();
        }

        /// <summary>
        /// Gets the patient ID.
        /// </summary>
        public string ID 
        {
            get { return id; }
        }

        /// <summary>
        /// Gets and sets the sex type.
        /// </summary>
        public SexType Sex
        {
            get;
            set; 
        }

        /// <summary>
        /// Gets and sets the birthday.
        /// </summary>
        public DateTime Birthday
        {
            get;
            set; 
        }

        /// <summary>
        /// Gets and sets the department.
        /// </summary>
        public string Department 
        {
            get;
            set;
        }

        /// <summary>
        /// Gets and sets the admit timestamp.
        /// </summary>
        public DateTime Admit
        {
            get; 
            set;
        }

        /// <summary>
        /// Gets and sets the discharge timestamp.
        /// </summary>
        public DateTime Discharge
        {
            get; 
            set;
        }

        /// <summary>
        /// Gets and sets the cost fee.
        /// </summary>
        public double Cost
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the length of stay (LOS).
        /// </summary>
        public int LOS
        {
            get
            {
                return (int)(Discharge - Admit).TotalDays;
            }
        }

        /// <summary>
        /// Gets the diagnoses.
        /// </summary>
        public string[] Diagnoses
        {
            get
            {
                int count = diagnoses.Count;
                string[] ret = new string[count];
                for (int i = 0; i < count; i++)
                {
                    ret[i] = owner.GetDiagnosisType(diagnoses[i]);
                }
                return ret;
            }
        }

        /// <summary>
        /// Gets the count of diagnosis.
        /// </summary>
        public int DiagnosisLength
        {
            get { return diagnoses.Count; }
        }

        /// <summary>
        /// Gets the observations.
        /// </summary>
        public List<ObservationEvent> Observations
        {
            get { return observations; }
        }

        /// <summary>
        /// Gets the count of observations.
        /// </summary>
        public int ObservationLength
        {
            get { return observations.Count; }
        }

        /// <summary>
        /// Gets the actions.
        /// </summary>
        public List<ActionEvent> Actions
        {
            get { return actions; }
        }

        /// <summary>
        /// Gets the count of actions.
        /// </summary>
        public int ActionLength
        {
            get { return actions.Count; }
        }

        /// <summary>
        /// Gets the owner LogModel, called by ClinicalEvent instance.
        /// </summary>
        internal LogModel Owner
        {
            get { return owner; }
        }

        /// <summary>
        /// Adds diagnosis to trace, called when parsing log file.
        /// </summary>
        /// <param name="name">Diagnosis name</param>
        public void AddDiagnosis(string name)
        {
            int index = owner.AddDiagnosisType(name);
            if (diagnoses.Contains(index))
                return;
            diagnoses.Add(index);
        }

        /// <summary>
        /// Adds observation to trace, called when parsing log file.
        /// </summary>
        /// <param name="entry">Observation entry</param>
        public void AddObservation(ObservationEvent entry)
        {
            if (observations.Contains(entry))
                return;

            foreach (var item in observations)
            {
                if (item.CompareTo(entry) == 0 && item.TypeIndex == entry.TypeIndex)
                    return;
            }
            observations.Add(entry);
        }

        /// <summary>
        /// Adds action to trace, called when parsing log file.
        /// </summary>
        /// <param name="entry">Action entry</param>
        public void AddAction(ActionEvent entry)
        {
            if (actions.Contains(entry))
                return;

            foreach (var item in actions)
            {
                if (item.CompareTo(entry) == 0 && item.TypeIndex == entry.TypeIndex)
                    return;
            }
            actions.Add(entry);
        }

        /// <summary>
        /// Orders the observation and action events, called when parsing log file.
        /// </summary>
        public void OrderTrace()
        {
            ObservationEvent.OrderEvents(observations);
            ActionEvent.OrderEvents(actions);
        }
    }
}
